/**
 * 
 */
package name.yzhu.httpserver.method;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.google.common.base.Splitter;

import name.yzhu.common.lang.Bytes;
import name.yzhu.common.lang.LangUtil;

/**
 * @author yhzhu
 *
 */
public class Http2Method {
	private static final Log LOG = LogFactory.getLog(Http2Method.class);
	
	private String[] params = null;
	private Class<?>[] paramsTypes = null;
	private Method method = null;
	private IHttpHandler handler;
	private MethodDelcleare md;
	
	public Http2Method(IHttpHandler handler, Method method, MethodDelcleare md){
		HttpMethodAnno hma = method.getAnnotation(HttpMethodAnno.class);
    	if (hma == null)
    		throw new NoSuchMethodError("there is no anntation HttpMethodAnno in "+method.getName());
    	
		this.handler = handler;
		this.method = method;
		this.setMd(md);
		this.paramsTypes = method.getParameterTypes();
		 List<String> parameters = md.getParameterNames();
		if (parameters == null || parameters.size() == 0)
			params = new String[0];
		else
		    params = parameters.toArray(new String[0]);	
	}
	
	public byte[] invokeFromHttpReqest(HttpServletRequest req, 
			HttpServletResponse res) 
	throws IllegalArgumentException, 
	IllegalAccessException, InvocationTargetException{
		Object args[] = new Object[this.paramsTypes.length];
		if (md.isNaiveMethod()){
			args[0] = req;
			args[1] = res;
		}
		else {
			for (int i=0; i<paramsTypes.length; ++i){
				Class<?>  pt = paramsTypes[i];
				String name = params[i];
				String value = req.getParameter(name);
				if (value == null){
					args[i] = null;
				}
				else {
				    if (List.class.isAssignableFrom(pt)){
				    	args[i] = parseValue2StringList(value);
				    }
				    else if (Map.class.isAssignableFrom(pt)){
				    	args[i] = parseValue2StringMap(name, value);
				    }
				    else {
				    	args[i] = LangUtil.converte2PrimaryType(pt, value);
				    }
				}
			}
		}
		try {
			md.getMethodAuthorized().check(req, res, md);
		} catch (IllegalAccessException e) {
			LOG.error("illegal authorized for "+this.method.getName(), e);
			throw e;
		}
		
		byte[] result = (byte[]) method.invoke(handler, args);
		return Bytes.toBytes(result);
	}
	
	public IHttpHandler getHandler() {
		return handler;
	}
	public void setHandler(IHttpHandler handler) {
		this.handler = handler;
	}
	public String[] getParams() {
		return params;
	}
	public Class<?>[] getMethodParamsTypes() {
		return paramsTypes;
	}
	public Method getMethod() {
		return method;
	}

	public void setMd(MethodDelcleare md) {
		this.md = md;
	}

	public MethodDelcleare getMd() {
		return md;
	}
	
	private List<String> parseValue2StringList(String pvalue) {
		Iterable<String> iter = Splitter.on(',').split(pvalue);
		List<String> list = new ArrayList<String>();
		Iterator<String> iterator = iter.iterator();
		while(iterator.hasNext()){
			list.add(iterator.next());
		}
		return list;
	}
	
	private Map<String, String> parseValue2StringMap(String name, String pvalue){
		Map<String, String> map = new LinkedHashMap<String, String>();
		Iterable<String> iter = Splitter.on(',').split(pvalue);
		Iterator<String> iterator = iter.iterator();
		while(iterator.hasNext()){
			String[] value = iterator.next().split(":");
			if (value.length != 2)
				throw new IllegalArgumentException("invalid map, please check "+name);
			map.put(value[0], value[1]);
		}
		return map;
	}

}
